package com.xhj.mybatis.mapping;

import com.xhj.mybatis.cache.Cache;
import com.xhj.mybatis.cache.decorators.*;
import com.xhj.mybatis.cache.impl.PerpetualCache;
import com.xhj.mybatis.reflection.MetaObject;
import com.xhj.mybatis.reflection.SystemMetaObject;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * CacheBuilder
 *
 * @author XJks
 * @description TODO:CacheBuilder 主要构建的是全局的一级缓存对象 Cache。它采用了建造者模式，允许用户通过链式调用的方式配置缓存的各种属性，如实现类、装饰器、大小、清理间隔等。最终通过 build() 方法构建出一个完整配置的 Cache 实例。
 */
public class CacheBuilder {
    /**
     * 缓存的唯一标识符
     */
    private final String id;

    /**
     * 缓存实现类（如 PerpetualCache）
     */
    private Class<? extends Cache> implementation;

    /**
     * 缓存装饰器列表（如 LruCache、LoggingCache 等）
     */
    private final List<Class<? extends Cache>> decorators;

    /**
     * 缓存大小
     */
    private Integer size;

    /**
     * 缓存清理间隔（毫秒）
     */
    private Long clearInterval;

    /**
     * 是否启用读写序列化
     */
    private boolean readWrite;

    /**
     * 缓存属性配置
     */
    private Properties properties;

    /**
     * 是否启用阻塞缓存
     */
    private boolean blocking;

    /**
     * 构造方法，初始化 id 和装饰器列表
     *
     * @param id 缓存的唯一标识符
     */
    public CacheBuilder(String id) {
        this.id = id;
        this.decorators = new ArrayList<>();
    }

    /**
     * 设置缓存实现类
     *
     * @param implementation 缓存实现类
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder implementation(Class<? extends Cache> implementation) {
        this.implementation = implementation;
        return this;
    }

    /**
     * 添加缓存装饰器
     *
     * @param decorator 缓存装饰器类
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder addDecorator(Class<? extends Cache> decorator) {
        if (decorator != null) {
            this.decorators.add(decorator);
        }
        return this;
    }

    /**
     * 设置缓存大小
     *
     * @param size 缓存大小
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder size(Integer size) {
        this.size = size;
        return this;
    }

    /**
     * 设置缓存清理间隔
     *
     * @param clearInterval 缓存清理间隔（毫秒）
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder clearInterval(Long clearInterval) {
        this.clearInterval = clearInterval;
        return this;
    }

    /**
     * 设置是否启用读写序列化
     *
     * @param readWrite 是否启用读写序列化
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder readWrite(boolean readWrite) {
        this.readWrite = readWrite;
        return this;
    }

    /**
     * 设置是否启用阻塞缓存
     *
     * @param blocking 是否启用阻塞缓存
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder blocking(boolean blocking) {
        this.blocking = blocking;
        return this;
    }

    /**
     * 设置缓存属性
     *
     * @param properties 缓存属性
     * @return 当前 CacheBuilder 实例
     */
    public CacheBuilder properties(Properties properties) {
        this.properties = properties;
        return this;
    }

    /**
     * 构建缓存对象
     *
     * @return 构建好的缓存实例
     */
    public Cache build() {
        // 设置默认的缓存实现和装饰器（如果未指定）
        setDefaultImplementations();
        // 创建基础缓存实例（如 PerpetualCache），传入 id
        Cache cache = newBaseCacheInstance(implementation, id);
        // 设置缓存的属性（如 size、clearInterval 等）
        setCacheProperties(cache);
        // 如果是自定义缓存实现，不应用装饰器
        if (PerpetualCache.class.equals(cache.getClass())) {
            // 依次为基础缓存添加自定义装饰器
            for (Class<? extends Cache> decorator : decorators) {
                // 用装饰器包装缓存
                cache = newCacheDecoratorInstance(decorator, cache);
                // 设置装饰器缓存的属性
                setCacheProperties(cache);
            }
            // 添加标准装饰器（如定时清理、序列化、日志、同步、阻塞等）
            cache = setStandardDecorators(cache);
        } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
            // 如果不是 LoggingCache 的子类，则再包一层日志装饰器
            cache = new LoggingCache(cache);
        }
        // 返回最终构建好的缓存对象
        return cache;
    }

    /**
     * 设置默认的缓存实现和装饰器
     */
    private void setDefaultImplementations() {
        if (implementation == null) {
            // 默认实现为 PerpetualCache
            implementation = PerpetualCache.class;
            if (decorators.isEmpty()) {
                // 默认装饰器为 LruCache
                decorators.add(LruCache.class);
            }
        }
    }

    /**
     * 添加标准装饰器（如定时清理、序列化、日志、同步、阻塞等）
     *
     * @param cache 基础缓存实例
     * @return 添加装饰器后的缓存实例
     */
    private Cache setStandardDecorators(Cache cache) {
        try {
            // 通过反射设置缓存属性
            MetaObject metaCache = SystemMetaObject.forObject(cache);
            if (size != null && metaCache.hasSetter("size")) {
                metaCache.setValue("size", size);
            }
            // 如果设置了清理间隔，则添加定时清理装饰器
            if (clearInterval != null) {
                cache = new ScheduledCache(cache);
                ((ScheduledCache) cache).setClearInterval(clearInterval);
            }
            // 如果启用读写序列化，则添加序列化装饰器
            if (readWrite) {
                cache = new SerializedCache(cache);
            }
            // 添加日志装饰器
            cache = new LoggingCache(cache);
            // 添加同步装饰器
            cache = new SynchronizedCache(cache);
            // 如果启用阻塞，则添加阻塞装饰器
            if (blocking) {
                cache = new BlockingCache(cache);
            }
            return cache;
        } catch (Exception e) {
            // 构建装饰器失败抛出异常
            throw new RuntimeException("Error building standard cache decorators.  Cause: " + e, e);
        }
    }

    /**
     * 设置缓存属性
     *
     * @param cache 缓存实例
     */
    // 设置缓存属性
    private void setCacheProperties(Cache cache) {
        // 如果属性不为空，则进行设置
        if (properties != null) {
            // 通过反射机制获取缓存对象的元数据，方便后续动态设置属性
            MetaObject metaCache = SystemMetaObject.forObject(cache);
            // 遍历所有属性项
            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
                // 获取属性名
                String name = (String) entry.getKey();
                // 获取属性值
                String value = (String) entry.getValue();
                // 判断缓存对象是否有对应的 setter 方法
                if (metaCache.hasSetter(name)) {
                    // 获取 setter 方法参数类型
                    Class<?> type = metaCache.getSetterType(name);
                    // 根据属性类型进行转换并设置值
                    if (String.class == type) {
                        // 如果是字符串类型，直接设置
                        metaCache.setValue(name, value);
                    } else if (int.class == type || Integer.class == type) {
                        // 如果是 int 或 Integer 类型，转换为整数后设置
                        metaCache.setValue(name, Integer.valueOf(value));
                    } else if (long.class == type || Long.class == type) {
                        // 如果是 long 或 Long 类型，转换为长整型后设置
                        metaCache.setValue(name, Long.valueOf(value));
                    } else if (short.class == type || Short.class == type) {
                        // 如果是 short 或 Short 类型，转换为短整型后设置
                        metaCache.setValue(name, Short.valueOf(value));
                    } else if (byte.class == type || Byte.class == type) {
                        // 如果是 byte 或 Byte 类型，转换为字节型后设置
                        metaCache.setValue(name, Byte.valueOf(value));
                    } else if (float.class == type || Float.class == type) {
                        // 如果是 float 或 Float 类型，转换为浮点型后设置
                        metaCache.setValue(name, Float.valueOf(value));
                    } else if (boolean.class == type || Boolean.class == type) {
                        // 如果是 boolean 或 Boolean 类型，转换为布尔型后设置
                        metaCache.setValue(name, Boolean.valueOf(value));
                    } else if (double.class == type || Double.class == type) {
                        // 如果是 double 或 Double 类型，转换为双精度浮点型后设置
                        metaCache.setValue(name, Double.valueOf(value));
                    } else {
                        // 如果类型不支持，则抛出异常
                        throw new RuntimeException("Unsupported property type for cache: '" + name + "' of type " + type);
                    }
                }
            }
        }
        // todo:源码这里存在处理 InitializingObject 接口的逻辑，目前没必要，暂不实现，
    }

    /**
     * 创建基础缓存实例（如 PerpetualCache），通过反射调用构造方法
     *
     * @param cacheClass 缓存类
     * @param id         缓存唯一标识符
     * @return 缓存实例
     */
    private Cache newBaseCacheInstance(Class<? extends Cache> cacheClass, String id) {
        // 获取缓存类的构造方法（参数为 String 类型的 id）
        Constructor<? extends Cache> cacheConstructor = getBaseCacheConstructor(cacheClass);
        try {
            // 通过反射调用构造方法，创建缓存实例，并传入 id 作为参数
            return cacheConstructor.newInstance(id);
        } catch (Exception e) {
            // 如果实例化过程中出现异常，则抛出自定义的 CacheException，并附带异常信息
            throw new RuntimeException("Could not instantiate cache implementation (" + cacheClass + "). Cause: " + e, e);
        }
    }

    /**
     * 获取基础缓存的构造方法（参数为 String id）
     *
     * @param cacheClass 缓存类
     * @return 构造方法
     */
    private Constructor<? extends Cache> getBaseCacheConstructor(Class<? extends Cache> cacheClass) {
        try {
            // 尝试通过反射获取 cacheClass 类中，参数为 String 类型的构造方法
            return cacheClass.getConstructor(String.class);
        } catch (Exception e) {
            // 如果获取构造方法失败（比如没有这个构造方法），则抛出自定义异常，并附带详细错误信息
            throw new RuntimeException(
                    "Invalid base cache implementation (" + cacheClass + ").  "
                            + "Base cache implementations must have a constructor that takes a String id as a parameter.  Cause: " + e, e
            );
        }
    }

    /**
     * 创建装饰器缓存实例，通过反射调用构造方法
     *
     * @param cacheClass 装饰器类
     * @param base       基础缓存实例
     * @return 装饰器缓存实例
     */
    private Cache newCacheDecoratorInstance(Class<? extends Cache> cacheClass, Cache base) {
        // 通过 getCacheDecoratorConstructor 方法获取装饰器类的构造方法（参数为 Cache 类型）
        Constructor<? extends Cache> cacheConstructor = getCacheDecoratorConstructor(cacheClass);
        try {
            // 使用反射机制，调用构造方法，传入 base 作为参数，创建装饰器实例
            return cacheConstructor.newInstance(base);
        } catch (Exception e) {
            // 如果实例化过程中出现异常，则抛出自定义的 CacheException，并附带异常信息
            throw new RuntimeException("Could not instantiate cache decorator (" + cacheClass + "). Cause: " + e, e);
        }
    }

    /**
     * 获取装饰器的构造方法（参数为 Cache base）
     *
     * @param cacheClass 装饰器类
     * @return 构造方法
     */
    private Constructor<? extends Cache> getCacheDecoratorConstructor(Class<? extends Cache> cacheClass) {
        try {
            // 通过反射机制，尝试获取 cacheClass 类中参数为 Cache 类型的构造方法
            return cacheClass.getConstructor(Cache.class);
        } catch (Exception e) {
            // 如果获取构造方法失败（比如没有这个构造方法），则抛出自定义异常，并附带详细错误信息
            throw new RuntimeException("Invalid cache decorator (" + cacheClass + ").  "
                    + "Cache decorators must have a constructor that takes a Cache instance as a parameter.  Cause: " + e, e);
        }
    }
}
